using System;
using System.Collections.Generic;

public class GooglePlayPurchasesAccessTokenForm
{
    // 请求:

    // curl https://accounts.google.com/o/oauth2/token \
    // -d 'grant_type=refresh_token' \
    // -d 'client_id=869370896681-332tthm5frve3b454umvv2bd7sfgu7mr.apps.googleusercontent.com' \
    // -d 'client_secret=LadUAViTfk-80rE4Si6D8Vlh' \
    // -d 'refresh_token=1/fWfXsDdpMqwKVg6KE9JCGvRsb9F9V_DtuEbqlDUAk-0'


    public string grant_type = "refresh_token";
    public string client_id;
    public string client_secret;
    public string refresh_token;
}

public class GooglePlayStoreConfig
{
    /// 客户端 ID
    public static string client_id;
    /// 客户端密钥
    public static string client_secret;
    /// 重定向url
    public static string redirect_uri;
    /// 永久的refresh_token
    public static string refresh_token;

    private static GooglePlayPurchasesAccessTokenForm _accessTokenForm;
    public static GooglePlayPurchasesAccessTokenForm accessTokenForm => _accessTokenForm;

    public static void SetConfigValue(string c_id, string c_secret, string r_token)
    {
        client_id = c_id;
        client_secret = c_secret;
        //redirect_uri = r_url;
        refresh_token = r_token;
        
        _accessTokenForm = new GooglePlayPurchasesAccessTokenForm()
        {
            client_id = c_id,
            client_secret = c_secret,
            refresh_token = r_token
        };
    }

    public static bool hasConfig
    {
        get
        {
            return (!string.IsNullOrEmpty(client_id)) &&
                   (!string.IsNullOrEmpty(client_secret)) &&
                   (!string.IsNullOrEmpty(redirect_uri)) &&
                   (!string.IsNullOrEmpty(refresh_token)) ;
        }
    }
    
    public static string CreateVerifyUrl(string packageName, string productId, string token, string access_token)
    {
        //https://www.googleapis.com/androidpublisher/v3/applications/<packageName>/purchases/products/<productId>/tokens/<token>?access_token=<access_token>
        return $"https://www.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/products/{productId}/tokens/{token}?access_token={access_token}";
    }
    
}

/// <summary>
/// Google Play Store 支付的常量
/// </summary>
public static class GooglePlayPurchaseConst
{
    public static class AcknowledgementState
    {
        /// <summary>
        /// 未确认
        /// </summary>
        public const int Yet_to_be_acknowledged = 0;
        /// <summary>
        /// 已确认
        /// </summary>
        public const int Acknowledged = 1;

        public static string GetName(int value)
        {
            if (value == Yet_to_be_acknowledged)
            {
                return "Yet to be acknowledged";
            }

            if (value == Acknowledged)
            {
                return "Acknowledged";
            }

            return "unexpected value";
        }
    }
    public static class ConsumptionState
    {
        /// <summary>
        /// 未消耗
        /// </summary>
        public const int Yet_to_be_consumed = 0;
        /// <summary>
        /// 已消耗
        /// </summary>
        public const int Consumed = 1;
        
        public static string GetName(int value)
        {
            if (value == Yet_to_be_consumed)
            {
                return "Yet to be consumed";
            }

            if (value == Consumed)
            {
                return "Consumed";
            }

            return "unexpected value";
        }
    }
    public static class PurchaseState
    {
        /// <summary>
        /// 已支付
        /// </summary>
        public const int Purchased = 0;
        /// <summary>
        /// 支付取消
        /// </summary>
        public const int Canceled = 1;
        /// <summary>
        /// 正在支付
        /// </summary>
        public const int Pending = 2;
        
        public static string GetName(int value)
        {
            if (value == Purchased)
            {
                return "Purchased";
            }

            if (value == Canceled)
            {
                return "Canceled";
            }
            
            if (value == Pending)
            {
                return "Pending";
            }

            return "unexpected value";
        }
    }
    public static class PurchaseType
    {
        /// <summary>
        /// 测试
        /// </summary>
        public const int Test = 0;
        /// <summary>
        /// 兑换码
        /// </summary>
        public const int Promo = 1;
        /// <summary>
        /// 奖励
        /// </summary>
        public const int Rewarded = 2;
        
        public static string GetName(int value)
        {
            if (value == Test)
            {
                return "Test";
            }

            if (value == Promo)
            {
                return "Promo";
            }
            
            if (value == Rewarded)
            {
                return "Rewarded";
            }

            // other is standard
            return "standard";
        }
    }
}


public enum GooglePlayStorePurchaseVerifyResult
{
    // 请求粗偶
    HttpRequestError,
    // 假的凭据
    FakeReceipt,
    // 成功
    Success,
}



public class GooglePlayStoreReceiptVerify 
{
    private bool m_AllowTest;
    private string m_PurchasesToken;
    private string m_PackageName;
    private string m_ProductId;
   // private string m_InternalOder;
    private Action<GooglePlayStoreReceiptVerify> m_OnResult;

    public string receipt => m_PurchasesToken;
    
    private int m_RequestCount = 0;
    public int requestCount => m_RequestCount;
    private GooglePlayStorePurchaseVerifyResult m_ResultStatus;
    public GooglePlayStorePurchaseVerifyResult resultStatus => m_ResultStatus;

    public GooglePlayStoreReceiptVerify(
        bool allowTest,
        //string internalOder, 
        string purchasesToken, 
        string packageName,
        string productId,
        Action<GooglePlayStoreReceiptVerify> callBack // 回调
        )
    {
        m_AllowTest = allowTest;
       // m_InternalOder = internalOder;
        m_PurchasesToken = purchasesToken;
        m_PackageName = packageName;
        m_ProductId = productId;

        m_OnResult = callBack;
    }

    public void Verify()
    {
        // 增加一次请求次数
        ++m_RequestCount;
        
        // TODO 验证，是否允许同时存在多个accessToken
        this.GetAccessToken();
    }

    public static void TestGetAccessToken()
    {
        string accessTokenUrl = "https://accounts.google.com/o/oauth2/token";
        AsyncHttpRequest webRequest = new AsyncHttpRequest(accessTokenUrl);
        webRequest.webRequest.ContentType = "application/x-www-form-urlencoded";
        webRequest.onResponse = delegate(AsyncHttpRequest request)
        {
            GameDebug.Log(request.error);
            GameDebug.Log(request.response);
        };
        webRequest.POSTForm(GooglePlayStoreConfig.accessTokenForm);
    }

    private void GetAccessToken()
    {
        GameDebug.Log($"Start get access token for: {this.receipt}");
        // 请求:

        // curl https://accounts.google.com/o/oauth2/token \
        // -d 'grant_type=refresh_token' \
        // -d 'client_id=869370896681-332tthm5frve3b454umvv2bd7sfgu7mr.apps.googleusercontent.com' \
        // -d 'client_secret=LadUAViTfk-80rE4Si6D8Vlh' \
        // -d 'refresh_token=1/fWfXsDdpMqwKVg6KE9JCGvRsb9F9V_DtuEbqlDUAk-0'

        // 结果:
        // {
        //    "access_token": "ya29.GltDB8sN4c7IpFjJ_qwElqHUJCBV85btgIuPTiU6VAya7-XLj7UOe1TMF-yCUy7TauQ1d-qvrros25FXpO1HblZYYkB-aUPzt4SPX_RYjf0bd57oUtxSyBS80gqC",
        //    "expires_in": 3600,
        //    "scope": "https://www.googleapis.com/auth/androidpublisher",
        //    "token_type": "Bearer"
        // }
        
        string accessTokenUrl = "https://accounts.google.com/o/oauth2/token";
        AsyncHttpRequest webRequest = new AsyncHttpRequest(accessTokenUrl);
        webRequest.webRequest.ContentType = "application/x-www-form-urlencoded";
        webRequest.onResponse = OnGetAccessToken;
        webRequest.POSTForm(GooglePlayStoreConfig.accessTokenForm);
    }

    private void OnGetAccessToken(AsyncHttpRequest webRequest)
    {
        GameDebug.Log($"On get access token for: {this.receipt}");

        // 结果:
        //
        // 异常
        // {
        //    "error": "invalid_grant",
        //    "error_description": "Bad Request"
        // }
        //
        // 正常
        // {
        //    "access_token": "ya29.GltDB8sN4c7IpFjJ_qwElqHUJCBV85btgIuPTiU6VAya7-XLj7UOe1TMF-yCUy7TauQ1d-qvrros25FXpO1HblZYYkB-aUPzt4SPX_RYjf0bd57oUtxSyBS80gqC",
        //    "expires_in": 3600,
        //    "scope": "https://www.googleapis.com/auth/androidpublisher",
        //    "token_type": "Bearer"
        // }

        // request error
        if (!string.IsNullOrEmpty(webRequest.error))
        {
            // error
            GameDebug.LogError($"google play store purchase get access token request error: {webRequest.error}");
            
            this.OnHttpError();
            return;
        }
        
        GameDebug.Log($"google play store purchase get access token response: {webRequest.response}");
        
        // parse json
        try
        {
            Dictionary<string, object> json = MiniJSON.Json.Deserialize(webRequest.response) as Dictionary<string, object>;
            if (json == null)
            {
                // error
                GameDebug.LogError("google play store purchase get access token json parse error");
                
                this.OnHttpError();
                return;
            }

            if (!json.ContainsKey("access_token"))
            {
                // error
                
                this.OnHttpError();
                return;
            }
            
            string accessToken = (string)json["access_token"];

            this.OnGetAccessTokenSuccess(accessToken);

            m_RetryCount = 0;
            m_AccessToken = accessToken;
        }
        catch (Exception e)
        {
            // error
            GameDebug.LogError($"google play store purchase get access token: {e}");
            
            this.OnHttpError();
        }
    }

    int m_RetryCount;
    const int maxRetryCount = 5;
    string m_AccessToken;

    private void OnGetAccessTokenSuccess(string accessToken)
    {
        GameDebug.Log($"google play store purchase get access token: {accessToken}");
        
        string verifyUrl = GooglePlayStoreConfig.CreateVerifyUrl(m_PackageName, m_ProductId, m_PurchasesToken, accessToken);
        GameDebug.Log($"google play verifyUrl: {verifyUrl}");
        AsyncHttpRequest webRequest = new AsyncHttpRequest(verifyUrl);
        webRequest.webRequest.ContentType = "application/x-www-form-urlencoded";
        webRequest.onResponse = OnVerify;
        webRequest.GET();

    }
    
    // (Jan 1, 1970)
    static long ticks_1970 = new DateTime(1970, 1, 1).Ticks;

    private void OnVerify(AsyncHttpRequest webRequest)
    {
        if (!string.IsNullOrEmpty(webRequest.error))
        {
            // request error
            GameDebug.LogError($"google play purchase verify request error: {webRequest.error}");
            if (m_RetryCount >= maxRetryCount)
            {
                this.OnHttpError();
            }
            else
            {
                m_RetryCount++;

                GameDebug.LogError($"网络错误：{webRequest.error}  正在重试第{m_RetryCount}次");

                OnGetAccessTokenSuccess(m_AccessToken);
            }
            return;
        }
    
        //验证成功
        //{
        //    "kind": "androidpublisher#productPurchase",
        //    "purchaseTimeMillis": long,
        //    "purchaseState": integer,
        //    "consumptionState": integer,
        //    "developerPayload": string,
        //    "orderId": string,
        //    "purchaseType": integer, // 并非一定有
        //    "acknowledgementState": integer
        //}

        try
        {
            Dictionary<string, object> json = MiniJSON.Json.Deserialize(webRequest.response) as Dictionary<string, object>;
            if (json == null)
            {
                this.OnVerifyFail();
                return;
            }

            bool success =
                json.ContainsKey("kind") &&
                json.ContainsKey("purchaseTimeMillis") &&
                json.ContainsKey("purchaseState") &&
                json.ContainsKey("consumptionState") &&
                json.ContainsKey("developerPayload") &&
                json.ContainsKey("orderId") &&
                json.ContainsKey("acknowledgementState");
            if (!success)
            {
                this.OnVerifyFail();
                return;
            }

            // 参数文档:https://developers.google.com/android-publisher/api-ref/purchases/products
            
            
            // orderId	string
            // The order id associated with the purchase of the inapp product.
            // 订单id

            string orderId = (string) json["orderId"];

            
            // acknowledgementState	integer
            // The acknowledgement state of the inapp product. Possible values are:
            // 0. Yet to be acknowledged 还未确认
            // 1. Acknowledged 已确认
            int acknowledgementState = Convert.ToInt32(json["acknowledgementState"]);
            // 0 is ok
            // 1 is 重复确认
            
            
            
            // consumptionState	integer
            // The consumption state of the inapp product. Possible values are:
            // 0. Yet to be consumed 还未消耗
            // 1. Consumed 已消耗
            
            int consumptionState = Convert.ToInt32(json["consumptionState"]);
            // 0 is ok
            if (GooglePlayPurchaseConst.ConsumptionState.Consumed == consumptionState)
            {
                GameDebug.LogError($"orderId: {orderId} 已消耗？");
            }

            // developerPayload	string
            // A developer-specified string that contains supplemental information about an order.
            // 透传参数
            
            //string developerPayload = (string) json["developerPayload"];
            //developerPayload = DecodePayloadOfUnity3d(developerPayload);
            //GameDebug.Log($"check payload: {developerPayload} -> {m_InternalOder}");
            //if (developerPayload != m_InternalOder)
            //{
            //    this.OnVerifyFail();
            //    return;
            //}

            // kind	string
            // This kind represents an inappPurchase object in the androidpublisher service.
            // 这种类型代表androidpublisher服务中的inappPurchase对象。
            
            
            
            // purchaseState integer
            // The purchase state of the order. Possible values are:
            // 0. Purchased 支付成功
            // 1. Canceled 支出失败
            // 2. Pending 正在支付中
            
            int purchaseState = Convert.ToInt32(json["purchaseState"]);
            // 0 is ok
            if (GooglePlayPurchaseConst.PurchaseState.Purchased != purchaseState)
            {
                // 不是支付成功
                GameDebug.LogError($"purchaseState not Purchased");
            }

            // purchaseTimeMillis long
            // The time the product was purchased, in milliseconds since the epoch (Jan 1, 1970).
            
            long purchaseTimeMillis = Convert.ToInt64(json["purchaseTimeMillis"]);
            DateTime purchaseDataTime = new DateTime(ticks_1970 + purchaseTimeMillis * 10000);
            GameDebug.Log($"oderId: {orderId}, purchaseDataTime: {purchaseDataTime.ToShortTimeString()}");

            // purchaseType	integer
            // The type of purchase of the inapp product. This field is only set if this purchase was not made using the standard in-app billing flow. Possible values are:
            // 仅在非标准支付下才有参数
            // 0. Test (i.e. purchased from a license testing account) 测试
            // 1. Promo (i.e. purchased using a promo code) 兑换码
            // 2. Rewarded (i.e. from watching a video ad instead of paying) 奖励

            int purchaseType = -1;
            if (json.ContainsKey("purchaseType"))
            {
                purchaseType = Convert.ToInt32(json["purchaseType"]);
            }

            GameDebug.Log($"oderId: {orderId}, purchaseType: {GooglePlayPurchaseConst.PurchaseType.GetName(purchaseType)}");

            if (GooglePlayPurchaseConst.PurchaseState.Purchased == purchaseState)
            {
                // 是否允许测试
                if (!m_AllowTest)
                {
                    if (purchaseType == GooglePlayPurchaseConst.PurchaseType.Test)
                    {
                        this.OnVerifyFail();
                        return;
                    }
                }

                this.OnVerifySuccess();
            }
            else
            {
                this.OnVerifyFail();
            }
        }
        catch (Exception e)
        {
            GameDebug.Log($"google play store purchase verify exception: {e}");
            this.OnVerifyFail();
        }
    }

    private void OnHttpError()
    {
        m_ResultStatus = GooglePlayStorePurchaseVerifyResult.HttpRequestError;
        this.OnResult();
    }

    private void OnVerifyFail()
    {
        m_ResultStatus = GooglePlayStorePurchaseVerifyResult.FakeReceipt;
        this.OnResult();
    }
    private void OnVerifySuccess()
    {
        m_ResultStatus = GooglePlayStorePurchaseVerifyResult.Success;
        this.OnResult();
    }

    private void OnResult()
    {
        this.m_OnResult?.Invoke(this);
    }
    

    static string DecodePayloadOfUnity3d(string payloadOfUnity3d)
    {
        if (string.IsNullOrEmpty(payloadOfUnity3d))
        {
            return payloadOfUnity3d;
        }

        // [2019-07-16 08-57-01-616][LOG]: check payload: {"developerPayload":"YjhiNTBiYzZjYzAyNDA5NmE2NmJkODc4ZDE2YzY3MzM=\n","is_free_trial":false,"has_introductory_price_trial":false,"is_updated":false,"accountId":""} -> b8b50bc6cc024096a66bd878d16c6733
        // {"developerPayload":"YjhiNTBiYzZjYzAyNDA5NmE2NmJkODc4ZDE2YzY3MzM=\n","is_free_trial":false,"has_introductory_price_trial":false,"is_updated":false,"accountId":""}
        try
        {
            var json = MiniJSON.Json.Deserialize(payloadOfUnity3d) as Dictionary<string, object>;
            if (json == null)
            {
                GameDebug.LogError($"Decode payloadOfUnity3d: {payloadOfUnity3d}, error: json null");
                return payloadOfUnity3d;
            }

            string base64 = (string)json["developerPayload"];
            const string tail = "\\n";
            if (base64.EndsWith(tail))
            {
                base64 = base64.Substring(0, base64.Length - tail.Length);
            }

            byte[] data = Convert.FromBase64String(base64);
            return System.Text.Encoding.UTF8.GetString(data);
        }
        catch (Exception e)
        {
            GameDebug.LogError($"Decode payloadOfUnity3d: {payloadOfUnity3d}, error: {e.Message}");
            return payloadOfUnity3d;
        }
    }
}